package com.doubledragon.tiny.ioc.factory;

import com.doubledragon.tiny.aop.autoProxyCreator.BeanFactoryAware;
import com.doubledragon.tiny.ioc.BeanDefinition;
import com.doubledragon.tiny.ioc.BeanReference;
import com.doubledragon.tiny.ioc.PropertyValue;
import com.doubledragon.tiny.ioc.PropertyValues;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

/**
 * Created by dragon
 *
 * AbstractBeanFactory的实现, 实现了Bean的创建和自动装配功能
 */
public class AutowireCapableBeanFactory extends AbstractBeanFactory{

    /**
     * 初始化bean。
     * 利用beanDefinition中的bean对应的Class生成实例
     */
    @Override
    public Object doCreateBean(BeanDefinition beanDefinition) throws Exception{

        Object bean = createBeanInstance(beanDefinition);
        applyPropertyValue(bean, beanDefinition.getPropertyValues());

        return bean;

    }

    //创建bean
    private Object createBeanInstance(BeanDefinition beanDefinition) throws Exception{
        Object bean = beanDefinition.getBeanClass().newInstance();

        //设置bean到beanDefinition，以便其他引用该bean的对象不需要再重复创建
        //此处的逻辑其实是默认了这是个scop为singleton的bean
        beanDefinition.setBean(bean);

        //判断bean是否是BeanFactoryAware的子类
        if(bean instanceof BeanFactoryAware){
            ((BeanFactoryAware)bean).setBeanFactory(this);
        }
        return bean;
    }

    //设置属性
    private void applyPropertyValue(Object bean, PropertyValues propertyValues) throws Exception{
        List<PropertyValue> propertyValueList = propertyValues.getPropertyValueList();
        for (PropertyValue propertyValue : propertyValueList) {
//            Field field = bean.getClass().getDeclaredField(propertyValue.getName());
//            field.setAccessible(true);
            Object value = propertyValue.getValue();
            //判断是一个已经创建好的bean还是一个beanDefinitionReference
            if(value instanceof BeanReference){
                //如果是一个beanDefinitionReference
                BeanReference beanReference = (BeanReference) value;
                value = getBean(beanReference.getName());
            }
            try {
                //利用setter设置值
                Method declaredMethod = bean.getClass().getDeclaredMethod(
                        "set" + propertyValue.getName().substring(0, 1).toUpperCase()
                                + propertyValue.getName().substring(1), value.getClass());
                declaredMethod.setAccessible(true);

                declaredMethod.invoke(bean, value);
            } catch (NoSuchMethodException e) {
                //利用field设置值
                Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());
                declaredField.setAccessible(true);
                declaredField.set(bean, value);
            }
        }
    }
}
